package iceworld.fernado.file.impl;

import iceworld.fernado.consts.Constants;
import iceworld.fernado.entity.Field;
import iceworld.fernado.entity.Table;
import iceworld.fernado.file.ILoadResource;
import iceworld.fernado.resource.TypeBundle;
import iceworld.fernado.util.LogManager;
import iceworld.fernado.util.SystemResource;
import iceworld.fernado.util.Utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

public class LoadResource implements ILoadResource {

	private static final String ID = LoadResource.class.getName();
	
	private static final Logger log = LogManager.getLogger(ID);
	
	private static final String file = SystemResource.getInstance().getProjectFolder() + "/resource/dbstructure.xls";
	
	private Map<String, Table> tables = new LinkedHashMap<String, Table>();
	
	public LoadResource() {

	}
	
	public Map<String, Table> getTables() {
		return tables;
	}
	
	@Override
	public boolean readResources() {
		if (Utils.isEmpty(file)) {
			return false;
		}
		LoadProgress lp = new LoadProgress();
		lp.run();
		return true;
	}
	
	private String getRecords(final HSSFRow row, final boolean isTableName, String tableName) {
		if (Utils.isEmpty(tableName)) {
			tableName = createTableName(row);
		}
		log.log(Level.INFO, "TABLE NAME: " + tableName);
		createFieldMap(row, tableName);
		return tableName;
	}
	
	private String createTableName(final HSSFRow row) {
		String result = Constants.EMPTY_STRING;
		if (null != row.getCell((short) 0)) {
			String cell = getContent(row, 0);
			if (!Utils.isEmpty(cell)) {
				tables.put(cell, new Table(cell));
				result = cell;
			}
		}
		return result;
	}
	
	private void createFieldMap(final HSSFRow row, final String tableName) {
		int cellIndex = 0;
		Table table = tables.get(tableName);
		Field field = new Field();
		while (null != row.getCell((short) cellIndex)) {
			createField(field, row, cellIndex);
			cellIndex++;
		}
		table.addField(field);
		log.log(Level.INFO, "Field: " + field.toString());
		tables.put(tableName, table);
	}
	
	private void createField(final Field field, final HSSFRow row, int cellIndex) {
		String cell = getContent(row, cellIndex);
		if (0 == cellIndex) {
			field.setName(cell);
		} else if (1 == cellIndex) {
			field.setZhName(cell);
		} else if (2 == cellIndex) {
			field.setType(getType(cell));
		} else if (3 == cellIndex) {
			field.setNone(isNone(cell));
		} else if (4 == cellIndex) {
			field.setDefaultValue(cell);
		} else if (5 == cellIndex) {
			field.setPrimaryKey(isNone(cell));
		} else if (6 == cellIndex) {
			field.setComment(cell);
		}
	}
	
	private boolean isNone(String value) {
		boolean result = false;
		if (!Utils.isEmpty(value)) {
			if (value.equalsIgnoreCase(Constants.YES)) {
				result = true;
			}
		}
		return result;
	}
	
	private String getType(String value) {
		int indexOfLeftParenthesis = value.indexOf(Constants.LEFT_PARENTHESIS);
		if (indexOfLeftParenthesis > -1) {
			value = value.substring(0, indexOfLeftParenthesis);
		}
		return TypeBundle.getInstance().getTypes().get(value);
	}
	
	private String getContent(final HSSFRow row, final int cellIndex) {
		HSSFCell cell = row.getCell((short) cellIndex);
		if (null == cell) {
			return Constants.EMPTY_STRING;
		}
		if (HSSFCell.CELL_TYPE_STRING != cell.getCellType()) {
			return changeToString(cell);
		}
		return cell.getRichStringCellValue().getString();
	}

	private String changeToString(final HSSFCell cell) {
		switch (cell.getCellType()) {
		case HSSFCell.CELL_TYPE_NUMERIC: 
			return String.valueOf(cell.getNumericCellValue());
		case HSSFCell.CELL_TYPE_BOOLEAN:
			return String.valueOf(cell.getBooleanCellValue());
		case HSSFCell.CELL_TYPE_ERROR: 
			return String.valueOf(cell.getErrorCellValue());
		case HSSFCell.CELL_TYPE_FORMULA:
			return String.valueOf(cell.getCellFormula());
		default:
			return Constants.EMPTY_STRING;
		}
	}
	
	private class LoadProgress implements Runnable {
		private POIFSFileSystem fs = null;
		private HSSFWorkbook wb = null;
		private InputStream is = null;
		private HSSFSheet sheet = null;
		private HSSFRow row = null;
		
		public LoadProgress() {
			
		}
		
		@Override
		public void run() {
			doReadExcel();
		}
		
		private void readRecord() {
			int rowIndex = 0;
			int cycle = 0;
			boolean noRecord = false;
			boolean isTableName = true;
			row = sheet.getRow(rowIndex);
			String tableName = Constants.EMPTY_STRING;
			while (!noRecord) {
				while (null == row) {
					isTableName = true;
					tableName = Constants.EMPTY_STRING;
					cycle++;
					row = sheet.getRow(++rowIndex);
					if (null == row && 2 == cycle) {
						noRecord = true;
						break;
					}
					if (null != row) {
						noRecord = false;
						cycle = 0;
					}
					
				}
				if (!noRecord) {
					tableName = getRecords(row, isTableName, tableName);
					isTableName = false;
					row = sheet.getRow(++rowIndex);
				} 
			}
		}
		
		private void doReadExcel() {
			try {
				is = new FileInputStream(file);
				fs = new POIFSFileSystem(is);
				wb = new HSSFWorkbook(fs);
				sheet = wb.getSheetAt(0);
				readRecord();
			} catch (FileNotFoundException e) {
				log.log(Level.WARNING, "NO FILE EXISTS - " + file);
			} catch (IOException e) {
				log.log(Level.WARNING, "CANT OPEN THE FILE - " + file);
			} catch (Exception e) {
				log.log(Level.WARNING, "UNKNOW EXCEPTION");
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					log.log(Level.INFO, "CANT CLOSE THE FILE - " + file);
				}
			}
		}
	}

}
